package cn.wolfcode.wolf2w.business.service.impl;

import cn.wolfcode.wolf2w.business.api.RemoteDestinationService;
import cn.wolfcode.wolf2w.business.api.RemoteNoteContentService;
import cn.wolfcode.wolf2w.business.api.domain.Note;
import cn.wolfcode.wolf2w.business.api.domain.NoteAudit;
import cn.wolfcode.wolf2w.business.api.domain.NoteContent;
import cn.wolfcode.wolf2w.business.mapper.NoteMapper;
import cn.wolfcode.wolf2w.business.query.NoteQuery;
import cn.wolfcode.wolf2w.business.service.INoteCommentService;
import cn.wolfcode.wolf2w.business.service.INoteContentService;
import cn.wolfcode.wolf2w.business.service.INoteService;
import cn.wolfcode.wolf2w.business.util.*;

import cn.wolfcode.wolf2w.common.core.constant.SecurityConstants;
import cn.wolfcode.wolf2w.common.core.context.SecurityContextHolder;
import cn.wolfcode.wolf2w.common.core.utils.DateUtils;
import cn.wolfcode.wolf2w.common.redis.service.RedisService;
import cn.wolfcode.wolf2w.common.redis.util.RedisKeys;
import cn.wolfcode.wolf2w.member.api.RemoteUserInfoService;
import cn.wolfcode.wolf2w.member.api.domain.UserInfo;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

/**
 * 旅游日记Service业务层处理
 * 
 * @author hnz
 * @date 2025-09-16
 */
@Service
@Transactional
public class NoteServiceImpl extends ServiceImpl<NoteMapper,Note> implements INoteService {
    @Autowired
    private RemoteUserInfoService remoteUserInfoService;
    @Autowired
    private RemoteNoteContentService remoteNoteContentService;
    @Autowired
    private RemoteDestinationService remoteDestinationService;
    @Autowired
    private RedisService redisService;
    @Autowired
    private INoteContentService noteContentService;
    @Autowired
    private INoteCommentService noteCommentService;

    @Override
    public IPage<Note> queryPage(NoteQuery qo) {
        IPage<Note> page = new Page<>(qo.getCurrentPage(), qo.getPageSize());
        QueryWrapper<Note> wrapper = new QueryWrapper<>();
        wrapper.eq("is_public",1);
        if (qo.getTravelTimeType()!=null&&qo.getTravelTimeType()>0){
            TravelTimeType timeByType = TravelTimeType.getTimeByType(qo.getTravelTimeType());
            if (timeByType!=null&&timeByType.getMounths()!=null) {
                wrapper.in("DATE_FORMAT(travel_time,'%c')",timeByType.getMounths());
            }
        }
        if (qo.getConsumeType()!=null&&qo.getConsumeType()>0){
            ConsumeType consumeByType = ConsumeType.getConsumeByType(qo.getConsumeType());
            if (consumeByType!=null&&consumeByType.getMin()!=null&&consumeByType.getMax()!=null){
                wrapper.between("avg_consume",consumeByType.getMin(),consumeByType.getMax());
            }
        }
        if (qo.getDayType()!=null&&qo.getDayType()>0){
            DayType dayByType = DayType.getDayByType(qo.getDayType());
            if (dayByType!=null&&dayByType.getMinDay()!=null&&dayByType.getMaxDay()!=null){
                wrapper.between("days",dayByType.getMinDay(),dayByType.getMaxDay());
            }
        }
        if (qo.getOrderType()!=null&&qo.getOrderType()>0){
            OrderType orderByType = OrderType.getOrderByType(qo.getOrderType());
            if (orderByType!=null&&orderByType.getOrder()!=null&& !orderByType.getOrder().isEmpty()){
                wrapper.orderByDesc(orderByType.getOrder());
            }
        }
        if (qo.getOrderBy()!=null&& !qo.getOrderBy().isEmpty()){
            wrapper.orderByDesc(qo.getOrderBy());
        }
        //后台的高级搜索
        if (qo.getTitle()!=null&& !qo.getTitle().isEmpty()){
            wrapper.like("title",qo.getTitle());
        }
        if (qo.getIsPublic()!=null&&!qo.getIsPublic().isEmpty()){
            wrapper.eq("is_public",qo.getIsPublic());
        }
        if (qo.getStatus()!=null&& !qo.getStatus().isEmpty()){
            wrapper.eq("status",qo.getStatus());
        }
        IPage<Note> noteIPage = baseMapper.selectPage(page, wrapper);
        List<Note> noteList = noteIPage.getRecords();

        if (noteList==null||noteList.size()==0){
            return noteIPage;
        }

        //给游记加作者
        //获取作者Id
        Set<Long> uids = new HashSet<>();
        for (Note note : noteList) {
            if (note.getAuthorId()!=null){
                uids.add(note.getAuthorId());
            }
        }
        //批量查询作者
        Map<Long, UserInfo> userInfoMap=new HashMap<>();
        if (!uids.isEmpty()){
            for (Long uid : uids){
                userInfoMap.put(uid,remoteUserInfoService.getOne(uid, SecurityConstants.INNER).getData());
            }
        }

        for (Note note : noteList) {
            note.setAuthor(userInfoMap.get(note.getAuthorId()));
        }




        return noteIPage;
    }

    @Override
    public Note getNoteById(Long nid) {
        String key=noteHashInit(nid);
        Long reads = redisService.incrementCacheMapValue(key, "viewnum", 1);
        Note note = baseMapper.selectById(nid);
        note.setViewnum(reads);
        NoteContent noteContent = remoteNoteContentService.getOne(nid, SecurityConstants.INNER).getData();
        note.setContent(noteContent);
        UserInfo userInfo = remoteUserInfoService.getOne(note.getAuthorId(), SecurityConstants.INNER).getData();
        note.setAuthor(userInfo);



        //收藏部分
        Long uid = SecurityContextHolder.getUserId();
        if (uid!=null){
            String userCollectKey = RedisKeys.USER_NOTE_FAVOR.join(uid.toString());
            boolean isCollected = redisService.isCacheSetContains(userCollectKey, nid);
            note.setFavorFlag(isCollected);
        }else {
            note.setFavorFlag(false);
        }
        Map<String, Object> cacheMap = redisService.getCacheMap(key);
        if (cacheMap!=null&&cacheMap.get("favornum") != null){
            note.setFavornum(Long.valueOf(cacheMap.get("favornum").toString()));
        }
        if (cacheMap!=null&&cacheMap.get("thumbsupnum") != null){
            note.setThumbsupnum(Long.valueOf(cacheMap.get("thumbsupnum").toString()));
        }
        return note;
    }

    public void noteHashPersistence(){
        String hashkey=RedisKeys.NOTE_STATIS_HASH.join("*");
        Collection<String> keys = redisService.keys(hashkey);
        if (keys!=null&&keys.size()>0){
            for (String key : keys) {
                Map<String, Object> cacheMap = redisService.getCacheMap(key);
                lambdaUpdate().eq(Note::getId,cacheMap.get("id"))
                        .set(Note::getViewnum,cacheMap.get("viewnum"))
                        .set(Note::getReplynum,cacheMap.get("replynum"))
                        .set(Note::getFavornum,cacheMap.get("favornum"))
                        .set(Note::getSharenum,cacheMap.get("sharenum"))
                        .set(Note::getThumbsupnum,cacheMap.get("thumbsupnum"))
                        .update();
            }
        }
    }

    @Override
    public void audit(NoteAudit audit) {
        QueryWrapper<Note> wrapper = new QueryWrapper<>();
        wrapper.eq("id", audit.getId());
        Note note = baseMapper.selectOne(wrapper);
        note.setStatus(audit.getStatus());
        baseMapper.update(note,wrapper);
    }

    @Transactional
    @Override
    public int removeAll(Long[] ids) {
        noteCommentService.removeByNoteId(Arrays.stream(ids).collect(Collectors.toList()));
        noteContentService.removeByIds(Arrays.stream(ids).collect(Collectors.toList()));
        removeByIds(Arrays.stream(ids).collect(Collectors.toList()));
        return 0;
    }


    private String noteHashInit(Long nid) {
        String key = RedisKeys.NOTE_STATIS_HASH.join(nid.toString());
        if (!redisService.hasKey( key)){
            Note note = this.getById(nid);
            Map<String, Object> map = new HashMap<>();
            map.put("viewnum", Integer.valueOf(note.getViewnum().toString()));
            map.put("replynum", Integer.valueOf(note.getReplynum().toString()));
            map.put("favornum", Integer.valueOf(note.getFavornum().toString()));
            map.put("sharenum", Integer.valueOf(note.getSharenum().toString()));
            map.put("thumbsupnum", Integer.valueOf(note.getThumbsupnum().toString()));
            map.put("id", note.getId());
            redisService.setCacheMap(key, map);
        }
        return key;
    }

    @Override
    public List<Note> queryViewnnumTop3(Long destId) {
        QueryWrapper<Note> warpper = new QueryWrapper<>();
        QueryWrapper<Note> select = warpper.eq("dest_id", destId)
                .orderByDesc("viewnum")
                .last("limit 3")
                .select();
        return baseMapper.selectList(select);
    }

    @Override
    public Map<String, Object> collect(Long noteId) {
        Long uid = SecurityContextHolder.getUserId();
        String keynid=noteHashInit(noteId);


        String key = RedisKeys.USER_NOTE_FAVOR.join(uid.toString());
        if (!redisService.hasKey(key)){
            Set<Long> nids = new HashSet<>();
            nids.add(-1L);
            redisService.setCacheSet(key, nids);
        }

        boolean favorFlag =false;
        String hashkey = RedisKeys.NOTE_STATIS_HASH.join(noteId.toString());

        Note note = baseMapper.selectById(noteId);
        Long collect = 0L;
        if (redisService.isCacheSetContains(key, noteId)){
            //取消收藏
            collect = redisService.incrementCacheMapValue(hashkey, "favornum", -1);
            redisService.deleteCacheSetValue(key, noteId);
            //更新收藏数
            note.setFavornum(collect);
        }else{
            //添加收藏
            collect = redisService.incrementCacheMapValue(hashkey, "favornum", 1);
            redisService.addCacheSetValue(key, noteId);
            //更新收藏数
            note.setFavornum(collect);
            favorFlag =true;

        }
        //因为前端每次收藏都刷新一次导致增加一次阅读量，这里减1
        Long reads = redisService.incrementCacheMapValue(keynid, "viewnum", -1);
        note.setViewnum(reads);

        Map<String, Object> map = redisService.getCacheMap(hashkey);
        map.put("favornum", collect);
        map.put("favorFlag", favorFlag);
        return map;
    }

    @Override
    public void add(Note note) {
        System.out.println("=== 前端传递的旅游天数：" + note.getDays());
        System.out.println("=== 前端传递的出行人群：" + note.getPerson());
        // 关键日志：打印content是否为null（复制这行，运行后看控制台）
        System.out.println("=== 前端传递的NoteContent：" + note.getContent());
        System.out.println("=== 前端传递的NoteContent正文：" + (note.getContent() != null ? note.getContent().getContent() : "null"));

        note.setAuthorId(SecurityContextHolder.getUserId());
        note.setDestName(remoteDestinationService.getOne(note.getDestId(), SecurityConstants.INNER).getData().getName());
        note.setCreateTime(new Date());
        note.setIsPublic(Boolean.parseBoolean(note.getIsPublic())?"1":"0");
        note.setStatus("0");
        baseMapper.insert(note);
        remoteNoteContentService.add(note, SecurityConstants.INNER);
    }

    @Override
    public Map<String, Object> star(Long nid) {
        //注入uid
        Long uid = SecurityContextHolder.getUserId();
        //拼key
        String key = RedisKeys.USER_NOTE_THUMBSUP.join(nid.toString(), uid.toString());
        // -------------------------- 新增日志1：确认用户ID和键名 --------------------------
        System.out.println("[点赞日志] 用户ID：" + uid + "，笔记ID：" + nid + "，用户点赞次数键：" + key);
        //计算过期时间
        Date now=new Date();
        Date end= DateUtil.getEndDate(now);
        long seconds = DateUtil.getDateBetween(now, end);
        // -------------------------- 新增日志2：确认过期时间 --------------------------
        System.out.println("[点赞日志] 当天结束时间：" + end + "，键过期秒数：" + seconds);
        //判断redis中是否存在key，如果没有创建key设置为0
        if (!redisService.hasKey(key)){
            redisService.setCacheObject(key, 0, seconds, TimeUnit.SECONDS);
            // -------------------------- 新增日志3：确认键是否重复初始化 --------------------------
            System.out.println("[点赞日志] 键不存在，已初始化：" + key + "，初始值0，过期秒数：" + seconds);
        }
        //点赞次数++
        Long ret = redisService.incrementCacheObjectValue(key, 1);
        String hashkey = RedisKeys.NOTE_STATIS_HASH.join(nid.toString());
        // -------------------------- 新增日志4：确认点赞次数是否累加 --------------------------
        System.out.println("[点赞日志] 用户当前总点赞次数：" + ret);
        boolean result = false;
        //判断点赞次数是否超过3，如果超过则设置result为false
        if (ret<=3){
            result = true;
            redisService.incrementCacheMapValue(hashkey, "thumbsupnum", 1);
            // -------------------------- 新增日志5：有效点赞日志 --------------------------
            System.out.println("[点赞日志] 有效点赞（次数≤3），全局点赞数+1，哈希键：" + hashkey);
        }
        //查询统计数字map结构，并将result加入到map中
        Map<String, Object> cacheMap = redisService.getCacheMap(hashkey);
        cacheMap.put("result", result);

//        //额外因为前端每次都刷新一次这里需要减一个阅读量
//        Note note = baseMapper.selectById(nid);
//        Long reads = redisService.incrementCacheMapValue(hashkey, "viewnum", -1);
//        note.setViewnum(reads);

        // -------------------------- 新增日志7：最终返回状态 --------------------------
        System.out.println("[点赞日志] 此次点赞是否有效：" + result + "，当前全局点赞数：" + cacheMap.get("thumbsupnum"));

        //返回map
        return cacheMap;

    }


}
